//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <protocol.h>
#include "reply.h"
#include "gprocess.h"
#include "trace.h"

typedef struct _request_handler_t
{
    req_handler func;
    unsigned long request_size;
    unsigned long reply_size;
} request_handler_t;

static request_handler_t request_handlers[] = {
#define REQUEST_ENTRY(x) \
    {                    \
        (req_handler)req_##x, \
        sizeof(struct x##_request), \
        sizeof(struct x##_reply)    \
    },

    REQUEST_TABLE

#undef REQUEST_ENTRY
};

#define CENTRAL_CHANNEL L"ElCentral"

static void CentralRequestRoutine(PVoid arg);

EXTERN wchar_t exeName[];
EXTERN wchar_t exeArgs[];

ECode central_request_loop(void)
{
    Aura_ChannelId channelId, listenedId;
    ECode ec = NOERROR;

    ec = AuraIpcChannel_Create((Aura_PWChar)CENTRAL_CHANNEL, &listenedId);
    if (FAILED(ec)) {
        goto Exit;
    }

    //Create the Client Process
    //TRACE("exeName:%S,  exeArgs:%S\n", exeName, exeArgs);

    if (exeName[0] != L'\0') {
        CGhostProcess *pGhost = NULL;
        ec = CGhostProcess::S_Create(ThreadPriorityRank_Normal,
                                   3,
                                   exeName,
                                   exeArgs,
                                   &pGhost);
        if (FAILED(ec)) {
            goto Exit;
        }
        pGhost->Release();
    }

    while (1) {
        ec = AuraIpcChannel_WaitForConnection((Aura_PWChar)CENTRAL_CHANNEL, &listenedId, &channelId);
        if (FAILED(ec)) {
            continue;
        }

 //       TRACE("central_request_loop new channel connect, channelId:%d\n", channelId);

        ec = AuraThread_Create(CentralRequestRoutine,
                            (Aura_PVoid)channelId,
                            Aura_ThreadCreationFlag_Started,
                            AURA_NULL,
                            AURA_NULL);
        if (FAILED(ec)) {
            AuraIpcChannel_Destroy(channelId);
            goto Exit;
        }
    }

Exit:
    AuraIpcChannel_Destroy(listenedId);
    return ec;
}

static void CentralRequestRoutine(PVoid arg)
{
    ECode ec;
    Aura_ChannelId id;

    UInt32 reqNum;
    UInt32 data_count;
    UInt32 reply_size;
    struct central_request_info info;

    id = (Aura_ChannelId)arg;

    while (1) {
        ec = AuraIpcChannel_Read(id, &info, sizeof(struct central_request_info));
        if (FAILED(ec)) {
            goto Exit;
        }

        data_count = info.request_data_count;
        while (data_count--) {
            info.request_data[data_count].ptr = \
                Aura_malloc(info.request_data[data_count].size);
            if (!info.request_data[data_count].ptr) {
                ec = E_OUT_OF_MEMORY;
                goto Exit;
            }

            ec = AuraIpcChannel_Read(id, info.request_data[data_count].ptr,
                    (Aura_UInt32)info.request_data[data_count].size);
            if (FAILED(ec)) {
                goto Exit;
            }
        }

        //        clear_error();
        reqNum = info.u.request.request_header.reqNum;
        if (reqNum < 0 || reqNum >= REQ_MAX_REQUESTS) {
            ec = E_FAIL;
            goto Exit;
        }

        reply_size = request_handlers[reqNum].reply_size;
        ec = request_handlers[reqNum].func(&(info.u.request), &(info.u.reply));
        info.u.reply.reply_header.error = ec;

        ec = AuraIpcChannel_AsyncWrite(id, &info, (Aura_UInt32)reply_size);
        if (FAILED(ec)) {
            goto Exit;
        }

        data_count = info.reply_data_count;
        while (data_count--) {
            ec = AuraIpcChannel_AsyncWrite(id, info.reply_data[data_count].ptr,
                    (Aura_UInt32)info.reply_data[data_count].size);
            if (FAILED(ec)) {
                goto Exit;
            }
        }

        while (info.request_data_count--)
            Aura_free(info.request_data[info.request_data_count].ptr);
        // do not free the reply data.    
    }

Exit:
    AuraIpcChannel_Destroy(id);
 // TODO: we should add some code here.
    return;
}

DECL_HANDLER(test)
{
    Aura_printf("==========:test handler: %d\n", req->val);
    return 0;
}
